<?php
declare(strict_types=1);

namespace Service\PayService;

use Service\BaseService;
use Service\Code\Normal;
use Service\StoreCardService\StoreCardService;
use App\Model\BbcModel\Member;
use Service\HelperService\StringService;
use App\Model\BbcModel\GoodsPointsConfig;

/**
 * 收银机支付中心
 * @author chenshubo
 */
class CashPayService extends BaseService
{
    const TYPE_CASH_PAY 		= 1;//现金支付
    const TYPE_SCAN_PAY 		= 2;//扫码付(被扫)
    const TYPE_SECE_PAY 		= 3;//扫码收(主扫)(根据系统配置的扫码支付)
    const TYPE_POS_PAY 	 		= 4;//pos机收款
    const TYPE_STORE_CARD_PAY  	= 5;//储值卡支付
    const TYPE_BALANCE_PAY  	= 6;//余额支付
    const TYPE_COUPON_PAY  		= 7;//优惠券
    const TYPE_PIONTS_PAY  		= 8;//积分支付
    const TYPE_WEIXIN_SCAN_PAY  = 9;//微信原生
    const TYPE_ALI_SCAN_PAY  	= 10;//支付宝原生
    const TYPE_GOODS_POINTS_PAY  	= 11;//积分抵现
    
    const PRODUCT_NORMAL_ORDER_PAY     ='normal';//普通订单
    const PRODUCT_BONDED_ORDER_PAY     ='bonded';//保税订单
    const PRODUCT_MEMBER_ORDER_PAY     ='member';//会员费订单
    const PRODUCT_BALANCE_ORDER_PAY    ='balance';//余额充值订单
    
    const AUTH_USER_PAY_WEIXIN =1; //用户授权支付类型。微信
    const AUTH_USER_PAY_ALIPAY =2; //用户授权支付类型,支付宝


    public $pay_way = 
    [
        0 => 'wxmnapp',//微信原生
        1 => 'hnapay',//新生支付
        2 => 'allinpay',//通联支付
        3 => 'alipay',//支付宝支付
        4 => 'easypay',//易生支付
        5 => 'helipay',//合利宝支付
    ];
    
    public  $auth_user_pay_type= [
        1 =>'微信支付',
        2 =>'支付宝支付'
    ];
    
    /**
     * 支付助手
     * @var unknown
     */
    public  $_cash_payer = 
    [
        self::TYPE_CASH_PAY         => [
            'pay_way'    => 'cashPay',
            'pay_name'   => '现金支付',
            'pay_code'   => 'cash',
            'is_support_bonded' => 0,
        ],
        self::TYPE_SCAN_PAY         => [
            'pay_way'    => 'scanPay',
            'pay_name'   => '扫码付款(被扫)',
            'pay_code'   => 'scan_pay',
            'is_support_bonded' => 0,
        ],
        self::TYPE_SECE_PAY         => [
            'pay_way'    => 'secePay',
            'pay_name'   => '扫码收款(主扫)',
            'pay_code'   => 'scan_rece',
            'is_support_bonded' => 1,
        ],
        self::TYPE_POS_PAY          => [
            'pay_way'    => 'posPay',
            'pay_name'   => 'pos机支付',
            'pay_code'   => 'pos',
            'is_support_bonded' => 0,
        ],
        self::TYPE_STORE_CARD_PAY   => [
            'pay_way'    => 'storeCardPay',
            'pay_name'   => '储值卡支付',
            'pay_code'   => 'storecard',
            'is_support_bonded' => 0,
        ],
        self::TYPE_BALANCE_PAY      => [
            'pay_way'    => 'balancePay',
            'pay_name'   => '余额支付',
            'pay_code'   => 'balance',
            'is_support_bonded' => 0,
        ],
        self::TYPE_COUPON_PAY       => [
            'pay_way'    => 'couponPay',
            'pay_name'   => '优惠券支付',
            'pay_code'   => 'coupon',
            'is_support_bonded' => 0,
        ],
        self::TYPE_PIONTS_PAY       => [
            'pay_way'    => 'pointsPay',
            'pay_name'   => '储值余额',
            'pay_code'   => 'points',
            'is_support_bonded' => 0,
        ],
        self::TYPE_WEIXIN_SCAN_PAY  => [
            'pay_way'    => 'weixinSanPay',
            'pay_name'   => '微信扫码支付',
            'pay_code'   => 'scan_rece',
            'is_support_bonded' => 1,
        ],
        self::TYPE_ALI_SCAN_PAY     => [
            'pay_way'    => 'aliScanPay',
            'pay_name'   => '支付宝扫码支付',
            'pay_code'   => 'scan_rece',
            'is_support_bonded' => 1,
        ],
        self::TYPE_GOODS_POINTS_PAY     => [
            'pay_way'    => 'goodspointsPay',
            'pay_name'   => '积分抵现',
            'pay_code'   => 'goods_points',
            'is_support_bonded' => 1,
        ],
    ];
    
    public  $_is_support_method=[
        self::TYPE_CASH_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY
        ],
        self::TYPE_SCAN_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY
        ],
        self::TYPE_SECE_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY,
            self::PRODUCT_BONDED_ORDER_PAY
        ],
        self::TYPE_POS_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY
        ],
        self::TYPE_STORE_CARD_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
        ],
        self::TYPE_BALANCE_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
        ],
        self::TYPE_COUPON_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
        ],
        self::TYPE_PIONTS_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
        ],
        self::TYPE_WEIXIN_SCAN_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY,
            self::PRODUCT_BONDED_ORDER_PAY
        ],
        self::TYPE_ALI_SCAN_PAY=>[
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_MEMBER_ORDER_PAY,
            self::PRODUCT_BALANCE_ORDER_PAY,
            self::PRODUCT_BONDED_ORDER_PAY
        ],
        self::TYPE_GOODS_POINTS_PAY     => [
            self::PRODUCT_NORMAL_ORDER_PAY,
            self::PRODUCT_BONDED_ORDER_PAY
        ],
    ];


    /**
     * mnid = 4 c端小程序
     * mnid = 2 大b小程序
     * 收银机支付功能
     * @param int $cid
     * @param int $mn_sid
     * @param array $extra
     */
    public function userPay(int $cid,int $mn_sid,int $mnid,array $extra)
    {
        if( !isset($extra['scan_rece_type']) ) {
            return Normal::returnCode(Normal::FAIL,"支付方式scan_rece_type缺失");
        }
        
        if( empty($extra['store_type']) ) {
            return Normal::returnCode(Normal::FAIL,"参数store_type类型缺失");
        }
        
        $scan_rece_type = (int)$extra['scan_rece_type'];
        if( !isset($this->pay_way[$scan_rece_type]) ) {
            return Normal::returnCode(Normal::FAIL,"支付方式scan_rece_type不支持，请联系管理配置!");
        }
        
        $pay_way    = ucfirst($this->pay_way[$scan_rece_type]);
        $className  = "Service\PayService\Payer\\{$pay_way}";
        $callMethod = 'scanPay';
        if (!class_exists($className)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】不存在");
        }
        if (!method_exists($className, $callMethod)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】方法【{$callMethod}】不存在");
        }
        
        try {
            
            $pay_result = $className::instance()->{$callMethod}($cid,$mn_sid,$mnid,$extra);
//            if( $pay_result['code'] != Normal::SUC ) {
//                return $pay_result;
//            }
//            
//            $orderExtendsData['scan_sn']=$pay['data']['transaction_id'];
//            Order::instance()->edit(['id'=> $order_insert_id], [
//                'pay_serial'        => $pay['data']['transaction_id'],
//                'initalRequest'     => $pay['data']['initalRequest'],
//                'initalResponse'    => $pay['data']['initalResponse']
//            ]);
            return $pay_result;
        } catch ( \Throwable $th ) {
            return Normal::returnCode(Normal::FAIL, "支付服务中心异常[{$th->getMessage()},{$th->getFile()},{$th->getLine()}]");
        }
    }
    
    
    /**
     * 根据前端提供支付参数确认支付信息
     * @param array $pay
     * @param array $param
     * @param string $method
     * @return type
     */
    public function getPayChannel(array $pay = [], array $param = [],string $method=self::PRODUCT_NORMAL_ORDER_PAY) {
        $pay_way = [];
        $money   = '0.00';
        $pay_type_maps= array_column($pay, 'pay_type');
        if(count(array_intersect($pay_type_maps,[self::TYPE_SECE_PAY,self::TYPE_WEIXIN_SCAN_PAY,self::TYPE_ALI_SCAN_PAY]))>1){
            return Normal::returnCode(Normal::FAIL, '扫码和扫脸不允许多种混合支付');
        }
        foreach ($pay as $key => $value)
        {
            if( empty($value['pay_type']) ) {
                return Normal::returnCode(Normal::FAIL,"支付方式参数缺失【pay_type】");
            }
            
            $pay_type = $value['pay_type'];
            if( !isset($this->_cash_payer[$pay_type]) ) {
                return Normal::returnCode(Normal::FAIL,"支付方式【{$pay_type}】不存在,请检查！");
            }
            
            //需要扫码code
            if( in_array($pay_type,[self::TYPE_SECE_PAY,self::TYPE_WEIXIN_SCAN_PAY,self::TYPE_ALI_SCAN_PAY]) ) 
            {
                if(isset($value['scan_code'])&&$value['scan_code']!='')
                {
                    $scan_code = $param['scan_code'] = $value['scan_code'];
                    
                    // 根据扫码的授权码更换支付方式。(微信和支付宝的扫码社保可以扫对方的码,固此处需判断切换)
                    $checkPayAuthCode = StringService::checkPayAuthCode($value['scan_code']);
                    
                    if( $pay_type == self::TYPE_WEIXIN_SCAN_PAY &&$checkPayAuthCode=='ALIPAY')
                    {
                        $pay_type = self::TYPE_ALI_SCAN_PAY;
                    }
                    
                    
                    if( $pay_type == self::TYPE_ALI_SCAN_PAY &&$checkPayAuthCode=='WECHATPAY')
                    {
                        $pay_type = self::TYPE_WEIXIN_SCAN_PAY;
                    }
                    
                    //付款码支付，微信限制
                    $scan_code  = str_replace(["\r\n","\r","\n"," "], "", $scan_code);
                    $_sub_pos   = substr($scan_code,0,2);
                    $_len_scan  = strlen($scan_code);
                    //合利宝取消限制
//                    if( ! (in_array($_sub_pos,['13']) && in_array($_len_scan,['18'])) )
//                    {
//                        return Normal::returnCode(Normal::FAIL, "当前客户订单支付结算仅支持【微信付款码】进行付款,请收银员核对客户出示的付款码[{$scan_code}]是否正确，感谢您的配合！");
//                    }
                }
                else
                {
                    return Normal::returnCode(Normal::FAIL,"支付方式【{$pay_type}】授权码未识别，请指导客户刷新付款码之后，重新扫码");
                }
            }
            
            $pay_way[] = $pay_type;
            $payer = $this->_cash_payer[$pay_type];
            if(!in_array($method, $this->_is_support_method[$pay_type])){
                return Normal::returnCode(Normal::FAIL, "支付方式【{$payer['pay_name']}】不支持该类型付款");
            }
            
            //当前支付方式支付金额
            $pay_money = (string)$value['pay_money'];
            $param[$payer['pay_code']] = $pay_money;
            $money = bcadd($money,$pay_money, 2);
            
            
            
            //储值卡支付
            if( $pay_type == self::TYPE_STORE_CARD_PAY ) 
            {
                $checkStoreCard = StoreCardService::instance()->checkStoredCard(
                    $param['cid'], 
                    $param['mn_sid'],
                    $value['cstorecard_num'],
                    $value['storecard_password'],
                    $value['pay_money']
                    );
                if( $checkStoreCard['code'] != Normal::SUC ) {
                    return $checkStoreCard;
                }
                
                $param['storecard_id'] = $checkStoreCard['data']['id'];
            }
            
            //积分支付（储值余额）
            if( $pay_type == self::TYPE_PIONTS_PAY ) 
            {
                if( !isset($param['mid']) ) {
                    return Normal::returnCode(Normal::FAIL, '使用储值余额的情况下,会员信息mid必传');
                }
                
                $member= Member::instance()->info(['mid'=>$param['mid']]);
                if(empty($member)){
                    return Normal::returnCode(Normal::FAIL, '会员信息错误');
                }
                
                if( $member['points'] < $pay_money ) {
                    return Normal::returnCode(Normal::FAIL, '会员储值余额不足');
                }
            }
            //积分抵现
            if($pay_type == self::TYPE_GOODS_POINTS_PAY){
                if( !isset($param['mid']) ) {
                    return Normal::returnCode(Normal::FAIL, '使用积分抵现的情况下,会员信息mid必传');
                }
                
                $member= Member::instance()->info(['mid'=>$param['mid']]);
                if(empty($member)){
                    return Normal::returnCode(Normal::FAIL, '会员信息错误');
                }
                if(empty($value['use_points'])||$value['use_points']<0){
                    return Normal::returnCode(Normal::FAIL, '积分抵扣使用积分（use_points）必传');
                }
                if( $member['goods_points'] < $value['use_points'] ) {
                    return Normal::returnCode(Normal::FAIL, '会员积分不足');
                }
                $pointsconfig= GoodsPointsConfig::instance()->info(['cid'=>$member['cid']]);
                if(empty($pointsconfig)){
                    return Normal::returnCode(Normal::FAIL, '该渠道未配置积分抵现');
                }
                if($pointsconfig['store_status']==0||$pointsconfig['points_use_store_status']!=1){
                    return Normal::returnCode(Normal::FAIL, '该渠道未开启积分抵现');
                }
                $param['use_points']=$value['use_points'];
            }
        }
        $param['pay_way'] = $pay_way;
        $price_order=$param['price_order']??0;
        $giveup_money=$param['giveup_money']??0;
        $all_pay_money= bcsub((string)$price_order, (string)$giveup_money,2);
        if(isset($param['price_order'])&&$all_pay_money!=$money){
            return Normal::returnCode(Normal::FAIL, '订单总金额和支付金额不一致');
        }
        if(isset($param['money'])&&$param['money']!=$money){
            return Normal::returnCode(Normal::FAIL, '总金额和支付金额不一致');
        }
        if(!isset($param['money'])){
            $param['money']=$money;
        }
        return Normal::returnCode(Normal::SUC,"获取成功",$param);
    }
    
    /**
     * 获取退款支付信息验证
     * @param array $pay
     * @param array $param
     * @return type
     */
    public function getReturnPayChannel(array $pay = [], array $param = []) {
        $pay_way = [];
        $money   = '0.00';
        $orderextends=$param['orderextends'];
        foreach ($pay as $key => $value)
        {
            if( empty($value['pay_type']) ) {
                return Normal::returnCode(Normal::FAIL,"支付方式参数缺失【pay_type】");
            }
            $pay_type = $value['pay_type'];
            if( !isset($this->_cash_payer[$pay_type]) ) {
                return Normal::returnCode(Normal::FAIL,"支付方式【{$pay_type}】不存在,请检查！");
            }
            $pay_way[] = $pay_type;
            $payer = $this->_cash_payer[$pay_type];
            $pay_code=$payer['pay_code'];
            //当前支付方式支付金额
            $pay_money = (string)$value['pay_money'];
            $param[$pay_code] = $pay_money;
            $money = bcadd($money,$pay_money, 2);
            if($orderextends[$pay_code]!=$value['pay_money']){
                return Normal::returnCode(Normal::FAIL, "支付方式【{$payer['pay_name']}】退款金额与消费金额不等");
            }
            
            if($pay_type == self::TYPE_STORE_CARD_PAY){
                $param['storecard_id']=$orderextends['storecard_id'];
            }
        }
        $totalmoney= bcadd($money, $orderextends['giveup_money'],2);
        if($totalmoney!=$param['price_order']){
            return Normal::returnCode(Normal::FAIL, "退款金额与消费金额不等");
        }
        $param['pay_way'] = $pay_way;
        return Normal::returnCode(Normal::SUC,"获取成功",$param);
    }
    
    /**
     * mnid = 4 c端小程序
     * mnid = 2 大b小程序
     * 收银机支付退款功能
     * @param int $cid
     * @param int $mn_sid
     * @param array $extra
     */
    public function userPayReturn(int $cid,int $mn_sid,int $mnid,array $extra)
    {
        if( !isset($extra['scan_rece_type']) ) {
            return Normal::returnCode(Normal::FAIL,"支付方式scan_rece_type缺失");
        }
        
        $scan_rece_type = (int)$extra['scan_rece_type'];
        if( !isset($this->pay_way[$scan_rece_type]) ) {
            return Normal::returnCode(Normal::FAIL,"支付方式scan_rece_type不支持，请联系管理配置!");
        }
        
        $pay_way    = ucfirst($this->pay_way[$scan_rece_type]);
        $className  = "Service\PayService\Payer\\{$pay_way}";
        $callMethod = 'scanPayRefund';
        if (!class_exists($className)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】不存在");
        }
        if (!method_exists($className, $callMethod)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】方法【{$callMethod}】不存在");
        }

        try {
            
            $pay_result = $className::instance()->{$callMethod}($cid,$mn_sid,$mnid,$extra);
            return $pay_result;
        } catch ( \Throwable $th ) {
            return Normal::returnCode(Normal::FAIL, "支付服务中心异常[{$th->getMessage()},{$th->getFile()},{$th->getLine()}]");
        }
    }
}
